package org.altervista.cp.thinjdbc;

import java.util.ArrayList;
import java.util.Iterator;

import org.altervista.cp.thinjdbc.wrappers.ResultSet;
import org.altervista.cp.thinjdbc.wrappers.SQLRuntimeException;

public class LoadQuery<T> extends Query<Iterable<T>> {

	public LoadQuery(String sql, ResultSetMapper<T> rsmapper, boolean connected) {
		super(sql.trim());
		if (!getSQLString().toLowerCase().startsWith("select")) {
			throw new SQLRuntimeException("Invalid SQL syntax: ["
					+ getSQLString() + "], instead of select");
		}
		_connected = connected;
		_rsmapper = rsmapper;
	}

	public ResultSetMapper<T> getResultSetMapper() {
		return _rsmapper;
	}

	public boolean isConnected() {
		return _connected;
	}

	protected Iterable<T> executeActivated() {
		final ResultSet rsw = getPreparedStatement().executeQuery();
		if (_connected) {
			if (_result == null) {
				_result = new Iterable<T>() {
					public Iterator<T> iterator() {
						return new Iterator<T>() {
							public boolean hasNext() {
								if (_next == null) {
									_next = rsw.next();
								}
								return _next;
							}

							public T next() {
								if (hasNext()) {
									_next = null;
									return _rsmapper.map(rsw);
								} else {
									throw new IndexOutOfBoundsException(
											"ResultSet finished");
								}
							}

							public void remove() {
								throw new UnsupportedOperationException();
							}

							private Boolean _next;
						};
					}
				};
			}
		} else {
			_result = new ArrayList<T>();
			while (rsw.next()) {
				((ArrayList<T>) _result).add(_rsmapper.map(rsw));
			}
		}
		return _result;
	}

	private boolean _connected;
	private ResultSetMapper<T> _rsmapper;
	private Iterable<T> _result;
}
